package com.java.digitalsignagesystem.utils;


import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;

import java.util.Map;
import java.util.TreeMap;

public class UKeyKit {

    private static final String baseUrl ="https://10.1.191.201:10006";
    private static final String appId = "APP_5DDEC7A73391402A879EE3C56432F695";
    private static final String secret = "c4njSCqaogjQPSFBPh2pldFnL3nxP9nU";
    private static final String deviceId = "DEV_2BA9F2AC77FA474DB77757E1DCF75950";

    /***
     * 返回随机数
     * @param randId 数据id,用于日志记录
     * @return
     */
    public static String genRandom(String randId) {
        Map<String, String> para = createPara(randId);
        para.put("length", "12");
        String post = requestPost("/chiron/v1/system/genRandom", para);
        return JSONUtil.parseObj(post).getJSONObject("data").getStr("random");
    }


    public static String createMainKey(String randId) {
        Map<String, String> para = createPara(randId);
        para.put("keyUsage", "ENCRYPT/DECRYPT");
        para.put("keySpec", "SM4_128");
        String post = requestPost("/chiron/v1/system/createKey", para);
        return JSONUtil.parseObj(post).getJSONObject("data").getJSONObject("cmkMetadata").getStr("keyId");
    }

    /***
     * 获取加密解密key,该key 需要全局缓存，可以按需获取不同的key 来进行获取与缓存keyId
     * @param randId
     * @return
     */

    public static String getKeyId(String randId) {
//        String keyId = createMainKey(randId);
        String keyId = "899e8987800e414685f122221ceacb20";

        return keyId;

    }

    /***
     * sm4 加密
     * @param data  数据
     * @param randId 随机数
     * @return
     */
    public static String sm4Encrypt(String data, String randId) {
        Map<String, String> para = createPara(randId);
        para.put("keyId", getKeyId(randId));
        para.put("mode", "ECB");
        para.put("padding", "PKCS7Padding");
        para.put("plainText", Base64.encode(data));
        return requestPost("/cmk/v1/encrypt", para);
    }

    /***
     * sm4 解密数据
     * @param data 数据
     * @param randId 随机数
     * @return
     */
    public static String sm4Decrypt(String data, String randId) {
        Map<String, String> para = createPara(randId);
        para.put("keyId", getKeyId(randId));
        para.put("encData", data);
        return requestPost("/cmk/v1/decrypt", para);
    }


    /***
     * 通用网络请求，请求前需要进行签名处理
     * @param url 请求地址
     * @param para 请求参数
     * @return
     */
    public static String requestPost(String url, Map<String, String> para) {
        getSignature(para);
        String post = HttpUtil.post(baseUrl + url, JSONUtil.toJsonStr(para));
        System.out.println(post);
        return post;
    }


    /***
     * 创建初始化参数，包含通用参数
     * @param randId 随机数，用于记录请求，用于排查问题
     * @return 返回通用参数
     */
    private static Map<String, String> createPara(String randId) {
        Map<String, String> para = new TreeMap<>();
        para.put("version", "1");
        para.put("signAlgo", "HmacSHA256");
        para.put("appId", appId);
        para.put("deviceId", deviceId);
        para.put("transId", randId);
        return para;
    }


    /***
     * 请求参数摘要签名
     * @param para
     * @return
     */
    public static String getSignature(Map<String, String> para) {
        String params = HttpUtil.toParams(para);
        String signature = SecureUtil.hmacSha256(secret).digestBase64(params, false);
        para.put("signature", signature);
        return signature;
    }

    /***
     * P1签名接口是指，调用方使用待签名数据作为入参，根据appId查询到保存的keyId信息，然后使用keyId查询到对应的密钥信息对待签名数据进行加密形成签名值。
     * @param randId
     * @return
     */
    public static String getCertByAppId(String randId) {
        Map<String, String> para = createPara(randId);
        String body = requestPost("/dsvs/v1/cert/getCertByAppId", para);
        return JSONUtil.parseObj(body).getJSONObject("data").getStr("result");
    }

    /***
     * P1签名接口是指，调用方使用待签名数据作为入参，根据appId查询到保存的keyId信息，然后使用keyId查询到对应的密钥信息对待签名数据进行加密形成签名值。
     * @param randId
     * @return
     */
    public static String sign(String source, String randId) {
        Map<String, String> para = createPara(randId);
        para.put("source", source);
        para.put("base64", "false");
        para.put("hash", "false");
        para.put("signAlg", "SM3withSM2");
        para.put("verifyCert", "true");
        String body = requestPost("/dsvs/v1/p1/sign", para);
        return JSONUtil.parseObj(body).getJSONObject("data").getStr("signValue");

    }

    /***
     * PKCS1原文验签接口，提供针对使用PKCS1原文签名接口产生的签名值进行验证的功能。需要注意的是，验签时使用的摘要算法必须与签名时使用的摘要算法相同，否则验签失败。
     * 4.1.5.PKCS1原文验签
     * @param signValue
     * @param oriData
     * @param base64Cert
     * @param randId
     * @return
     */
    public static String verifyDataSign(String signValue, String oriData, String base64Cert, String randId) {
        Map<String, String> para = createPara(randId);
        para.put("oriData", oriData);
        para.put("base64Cert", base64Cert);
        para.put("signValue", signValue);
        para.put("signAlgIdentifier", "SM3withSM2");
        para.put("verifyCert", "true");
        String body = requestPost("/dsvs/v1/pkcs1/verifyDataSign", para);
        return JSONUtil.parseObj(body).getJSONObject("data").getStr("result");

    }


    public static void main(String[] args) {
        String randId = RandomUtil.randomString(16);
        String signValue="MEUCIFUYoFx4hRkAay8/IqCzfbgH8Ze6+RdKqnJVjydPfmmVAiEAht0u8xR3K5OjzMllsCyCkIyTHvmUBDwpVW+KHEPRTK8=";
        String random="XHPueevInPnKIPk8";
        String certByAppId="MIIDgDCCAyagAwIBAgIKGhAAAAAAXAcGdDAKBggqgRzPVQGDdTBEMQswCQYDVQQGEwJDTjENMAsGA1UECgwEQkpDQTENMAsGA1UECwwEQkpDQTEXMBUGA1UEAwwOQmVpamluZyBTTTIgQ0EwHhcNMjQwMzE0MTYwMDAwWhcNMjUwMzE1MTU1OTU5WjB8MQswCQYDVQQGEwJDTjEbMBkGA1UECgwS5rWL6K+V5a+G5pyN5bqU55SoMS0wKwYDVQQLDCRBUFBfOTc0NUY3MzkyNURBNEFDRjhGMjYwMEUyMTVBRUNGRjIxITAfBgNVBAMMGOmHkeeJm+WfjuaKleaZuuaFp+a1i+ivlTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABDB/84WcHij6mzfPJSIADgLaSkYR+90+/85uwq98fDSXzyJQi+kz60jeu1H0QOAntK/JE9tefscKUrf5RaTAJlSjggHGMIIBwjAfBgNVHSMEGDAWgBQf5s/Uj8UiKpdKKYoV5xbJkjTEtjAdBgNVHQ4EFgQUCNBkSApx4ilHnLM4f5YojFNukaswDgYDVR0PAQH/BAQDAgbAMIGjBgNVHR8EgZswgZgwYKBeoFykWjBYMQswCQYDVQQGEwJDTjENMAsGA1UECgwEQkpDQTENMAsGA1UECwwEQkpDQTEXMBUGA1UEAwwOQmVpamluZyBTTTIgQ0ExEjAQBgNVBAMTCWNhMjFjcmwzMzA0oDKgMIYuaHR0cDovL3Rlc3QuYmpjYS5vcmcuY246ODAwMy9jcmwvY2EyMWNybDMzLmNybDATBgoqgRyG7zICAQEeBAUMAzUzODBrBggrBgEFBQcBAQRfMF0wKAYIKwYBBQUHMAGGHGh0dHA6Ly9vY3NwLmJqY2Eub3JnLmNuL29jc3AwMQYIKwYBBQUHMAKGJWh0dHA6Ly9vY3NwLmJqY2Eub3JnLmNuL0JKQ0FTTTJDQS5wN2IwPQYDVR0gBDYwNDAyBgkqgRyG7zICAgEwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly93d3cuYmpjYS5jbi9DUFMwCQYDVR0TBAIwADAKBggqgRzPVQGDdQNIADBFAiEAitg+X9J2zoB+uS8esv7VYNRcCTC9n7z6aceZDKXyf9wCIFdA0f+XUqzZU2oqQvjQMX7muYlZHxWQW4E9BQoizXY8";
        verifyDataSign(signValue,random,certByAppId,randId);


    }
}
